package com.lc.stock.module.filtrate;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import com.lc.stock.module.companyinfo.dao.CompanyInfoDao;
import com.lc.stock.module.companyinfo.domain.CompanyInfo;
import com.lc.stock.module.crawldata.CrawDataProcessService;
import com.lc.stock.module.excel.service.ExportSelectStockService;
import com.lc.stock.module.filtrate.filter.FiltrateStockFilterChain;
import com.lc.stock.module.filtrate.filter.bean.FilterResult;
import com.lc.stock.module.selectstockresult.dao.SelectStockResultDao;
import com.lc.stock.module.selectstockresult.domain.SelectStockResult;
import com.lc.stock.module.selectstockresult.domain.SelectStockResultDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lichen
 * @description 选股
 * @menu
 * @date 2023/2/6 16:56
 */
@Slf4j
@Service
public class SelectStockService {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private SelectStockResultDao selectStockResultDao;
    @Autowired
    private RetailInvestorAvgShareholding retailInvestorAvgShareholding;
    @Autowired
    private CrawDataProcessService crawDataProcessService;
    @Autowired
    private ExportSelectStockService exportSelectStockService;
    @Autowired
    private CompanyInfoDao companyInfoDao;

    //散户平均持股金额
    @Value("${retailInvestorAvg}")
    private int retailInvestorAvg;

    /**
     * 选股
     * @param filePath 通达信/国盛睿 导出的自选股板块 EBK 文件
     */
    public void selectStock(String filePath) throws Exception {
        /**
         * 1.解析EBK文件
         */
        List<String> list = FileUtil.readUtf8Lines(filePath);
        List<String> stockCodeList = list.stream().map(str -> {
            if(str.length() > 6){
                return str.substring(str.length() - 6);
            }else{
                return str;
            }
        }).collect(Collectors.toList());
        /**
         * 2.从麦蕊 获取股票相关数据
         */
        log.info("开始抓取数据。。。");
        LocalDateTime crawStartTime = LocalDateTime.now();

        crawDataProcessService.crawDataByStockCode(stockCodeList);

        LocalDateTime crawEndTime = LocalDateTime.now();
        Duration duration = Duration.between(crawStartTime,crawEndTime);
        long crawDuration = duration.toMillis();
        log.info("结束抓取数据，耗时{}",crawDuration);
        /**
         * 3.执行选股 并持久化到数据库
         */
        log.info("开始筛选股票。。。");
        LocalDateTime selectStartTime = LocalDateTime.now();

        selectStock(stockCodeList);

        LocalDateTime selectEndTime = LocalDateTime.now();
        Duration selectDuration = Duration.between(selectStartTime,selectEndTime);
        long selectDurationMillis = selectDuration.toMillis();
        log.info("结束筛选股票，耗时{}",selectDurationMillis);
        /**
         * 4.导出选中的股票信息（excel）
         */
        exportSelectStockService.export();
        log.info("导出文件成功");
    }

    /**
     * 执行选股
     * @param stockLists
     */
    public void selectStock(List<String> stockLists) throws Exception {
        //查询公司信息
        List<CompanyInfo> companyInfoList = companyInfoDao.findByStockCodeIn(stockLists);
        Map<String, CompanyInfo> companyInfoMap = companyInfoList.stream().collect(Collectors.toMap(
                key -> key.getStockCode(),
                v -> v,
                (a, b) -> a
        ));

        ArrayList<String> errorList = new ArrayList<>();

        //执行选股
        SelectStockResult selectStockResult = new SelectStockResult();
        LocalDate now = LocalDate.now();
        String currentDate = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        selectStockResult.setSelectStockDate(currentDate);
        //当前的选股结果
        ArrayList<SelectStockResultDetails> currentSelectList = new ArrayList<>();
        for (String stockCode : stockLists) {
            try{
                SelectStockResultDetails selectStockResultDetails = singleSelectStock(stockCode);
                CompanyInfo companyInfo = companyInfoMap.get(stockCode);
                if(null != companyInfo){
                    selectStockResultDetails.setName(companyInfo.getName());
                    selectStockResultDetails.setIdea(companyInfo.getIdea());
                }
                currentSelectList.add(selectStockResultDetails);
            }catch(Exception e){
                log.error(e.getMessage(),e);
                errorList.add(stockCode);
                continue;
            }

        }
        selectStockResult.setList(currentSelectList);


        //持久化入库
        SelectStockResult bySelectStockDate = selectStockResultDao.findBySelectStockDate(currentDate);
        if(null == bySelectStockDate || CollUtil.isEmpty(currentSelectList)){
            //当日未执行过选股，直接入库
            selectStockResultDao.insert(selectStockResult);
        }else{
            //当日执行过选股,用最新选股结果替换
            List<String> currentSelectStockCodeList = currentSelectList.stream().map(item -> item.getStockCode()).collect(Collectors.toList());
            //从数据库查询的结果中 筛选出当前没有选中的股票
            List<SelectStockResultDetails> remainList = bySelectStockDate.getList().stream()
                    .filter(item -> !currentSelectStockCodeList.contains(item.getStockCode()))
                    .collect(Collectors.toList());
            //合并
            remainList.addAll(currentSelectList);
            selectStockResultDao.deleteBySelectStockDate(currentDate);
            selectStockResult.setList(remainList);
            selectStockResultDao.insert(selectStockResult);
        }
        System.out.println("执行失败的个股：" + errorList.toString());
    }

    /**
     * 执行选股
     * @param stockCode
     * @return
     */
    public SelectStockResultDetails singleSelectStock(String stockCode) throws Exception {
        SelectStockResultDetails selectStockResultDetails = new SelectStockResultDetails();
        selectStockResultDetails.setStockCode(stockCode);
        selectStockResultDetails.setIfSelect(1);
        /**
         * 1.执行基本的过滤器链 选股
         */
        FiltrateStockFilterChain filtrateStockFilterChain = new FiltrateStockFilterChain(applicationContext);
        FilterResult filterResult = filtrateStockFilterChain.filter(stockCode);
        int ifSelect = filterResult.getIfSelect();
        if(ifSelect == 0){
            //未选中
            selectStockResultDetails.setIfSelect(filterResult.getIfSelect());
            selectStockResultDetails.setMessage(filterResult.getMessage());
        }

        /**
         * 2.执行 散户平均持股金额 算法
         */
        BigDecimal retailAvgAmount = retailInvestorAvgShareholding.compute(stockCode);
        selectStockResultDetails.setAvgAmount(retailAvgAmount);
        if(retailAvgAmount.compareTo(new BigDecimal(retailInvestorAvg)) >=0){
            selectStockResultDetails.setAvgAmountIfSatisfy("是");
        }else{
            selectStockResultDetails.setAvgAmountIfSatisfy("否");
        }
        return selectStockResultDetails;
    }

}
